package com.yhh;


import com.yhh.Entity.Command;
import com.yhh.Entity.HandlerCommand;
import com.yhh.Exceptions.ExitException;
import com.yhh.Exceptions.NonInstructionException;
import com.yhh.myUtils.CommandUtils;
import com.yhh.myUtils.Serializations;
import com.yhh.myUtils.myStringUtils;
import org.apache.log4j.Logger;

import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.security.InvalidKeyException;
import java.util.HashMap;
import java.util.Map;

import static com.yhh.Pipeline.path;
import static com.yhh.Pipeline.pipeline;


public class ServerThread extends Thread {
    // 和本线程相关的Socket
    private Socket socket = null;
    private BufferedReader br = null;
    private BufferedWriter bw = null;
    CommandUtils commandUtils = CommandUtils.getCommandUtils();
    //log日志输出
    public static Logger log = Server.log;

    StringBuilder msg = new StringBuilder();

    HashMap<String, HandlerCommand> commandMap = new HashMap<>();

    public ServerThread(Socket socket) throws IOException {
        this.socket = socket;
        this.br = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
        this.bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF-8"));
        commandMap.put("send", new SendCommand(socket));
        commandMap.put("recv", new RecvCommand(socket));
        commandMap.put("show", new ShowCommand(socket));
        commandMap.put("clear", new ClearCommand(socket));
    }

    // 线程执行的操作，响应客户端的请求
    public void run() {

        InetAddress address = socket.getInetAddress();
        System.out.println("新连接，客户端的IP：" + address.getHostAddress() + " ,端口：" + socket.getPort());
        log.info("新连接，客户端的IP：" + address.getHostAddress() + " ,端口：" + socket.getPort());
        try {
            // 获取输入流，并读取客户端信息
            String info = null;
            //获取key
            String key = recvMsg();
            if(!myStringUtils.decode(key)){
                //对暗号失败
                throw new InvalidKeyException();
            }
            //移除，用以客户端发起下次连接
            Server.remove(socket.getInetAddress());
            while (true) {
                if ((info = recvMsg()) != null) {
                    // 循环读取客户端的信息
                    log.info("ip为" + address.getHostAddress() + "的客户端说：" + info);
                    //处理指令
                    if (handlerCommand(info)) break;
                }
            }
        }catch (InvalidKeyException e){
            log.info("有不法分子！");
        }catch (Exception e) {
            sendMsg("出现异常");
            log.error("ip为" + address.getHostAddress() + "的客户端出现异常");
        } finally {
            log.info("客户端关闭：" + address.getHostAddress() + " ,端口：" + socket.getPort());
            // 关闭资源
            try {
                if (bw != null) {
                    bw.close();
                }
                if (br != null) {
                    br.close();
                }
                if (socket != null) {
                    socket.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public boolean handlerCommand(String info) {
        Map<String, String> args;
        //处理命令行提取指令
        try {
            //提取指令，不做检查
            args = CommandUtils.processCommand(info);
            if (args.isEmpty()) {
                throw new NonInstructionException();
            }
            //获取对应指令
            HandlerCommand command = commandMap.get(args.get("start"));
            if (command == null) throw new NonInstructionException();
            //检查参数是否正确
            commandUtils.checkCommandParameters(args, (Command) command);

            //执行命令
            command.handlerCommand(args);
        }catch (ExitException e){
            return true;
        }catch (NonInstructionException e) {
            sendMsg("空指令");
        } catch (Exception e) {
            System.out.println("出现异常");
            return true;
        }
        return false;
    }


    public static synchronized void save() {
        try {
            Serializations.serialize(path, pipeline);
            log.info("pipeline序列化成功");
        } catch (IOException e) {
            e.printStackTrace();
            log.error("pipeline序列化失败");
            log.error(e.getMessage());
        }
    }


    @Override
    public String toString() {
        return "ServerThread [socket=" + socket + "]";
    }

    protected void sendMsg(String s) {
        msg.append(s).append("\n");
        try {
            bw.write(msg.toString());
            //StringBuilder
            msg.delete(0, msg.length());
            // 调用flush()方法将缓冲输出
            bw.flush();
        } catch (IOException e) {

        }
    }

    //封装接受操作函数，增加可读性
    protected String recvMsg() throws IOException{
        String msg = null;
        msg = br.readLine();
        return msg;
    }
}
